package com.hsmpay.qian4.service.ds.impl;

import com.hsmpay.common.pojo.qian4.Qian4SendLog;
import com.hsmpay.mobile.action.account.scanCodePay.MD5;
import com.hsmpay.mobile.action.account.scanCodePay.ScanCodePayParam;
import com.hsmpay.mobile.action.account.scanCodePay.SignUtils;
import com.hsmpay.mobile.action.account.scanCodePay.XmlUtils;
import com.hsmpay.qian4.pojo.PurchaseResult;
import com.hsmpay.qian4.pojo.RevocationResult;
import com.hsmpay.qian4.service.ds.XYScanCodePayService;
import com.hsmpay.utils.DesUtil;
import com.hsmpay.utils.WriteFile;
import com.hsmpay.utils.system.ConConfig;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.util.*;

@Service("ds_XYScanCodePayService")
public class XYScanCodePayServiceImpl implements XYScanCodePayService {

    public static WriteFile wf = new WriteFile("ds_XYScan");
    private static Logger log = Logger.getLogger(XYScanCodePayServiceImpl.class);
    private static final String version = "1.0";
    private static final String charset = "UTF-8";
    public static final String mchId = "7551000001";
    private static final String MD5Key = "9d101c97133837e13dde2d32a5054abb";
    private static final String signType = "MD5";

    /**
     * 消费
     * @param send
     * @return
     * @throws Exception
     */
    public PurchaseResult purchase(Qian4SendLog send, ScanCodePayParam scanCodePayParam, String signatureRelPath) throws Exception {

        String service = "unified.trade.micropay";
        String notifyUrl = "";
        String reqUrl = "https://pay.swiftpass.cn/pay/gateway";

        String authCode = scanCodePayParam.getAuthCode();
        String body = StringUtils.isNotBlank(scanCodePayParam.getBody()) ? scanCodePayParam.getBody() : "花生米";
        String attach = scanCodePayParam.getAttach();
        String outTradeNo = scanCodePayParam.getOutTradeNo();
        int totalFee = Integer.valueOf(scanCodePayParam.getTotalFee());
        String deviceInfo = scanCodePayParam.getDeviceInfo();
        String spBillCreateIP = scanCodePayParam.getSpBillCreateIP();
        String timeStart = scanCodePayParam.getTimeStart();
        String timeExpire = scanCodePayParam.getTimeExpire();
        String goodsTag = scanCodePayParam.getGoodsTag();

        log.error("【扫码支付-收款 请求参数】authCode: "+ authCode);
        log.error("【扫码支付-收款 请求参数】body: "+ body);
        log.error("【扫码支付-收款 请求参数】attach: "+ attach);
        log.error("【扫码支付-收款 请求参数】outTradeNo: "+ outTradeNo);
        log.error("【扫码支付-收款 请求参数】totalFee: "+ totalFee);
        log.error("【扫码支付-收款 请求参数】deviceInfo: "+ deviceInfo);
        log.error("【扫码支付-收款 请求参数】spBillCreateIP: "+ spBillCreateIP);
        log.error("【扫码支付-收款 请求参数】timeStart: "+ timeStart);
        log.error("【扫码支付-收款 请求参数】timeExpire: "+timeExpire);
        log.error("【扫码支付-收款 请求参数】goodsTag: "+goodsTag);

        wf.log("【扫码支付-收款 请求参数】authCode: "+authCode, "调试");
        wf.log("【扫码支付-收款 请求参数】body: "+body, "调试");
        wf.log("【扫码支付-收款 请求参数】attach: "+attach, "调试");
        wf.log("【扫码支付-收款 请求参数】outTradeNo: "+outTradeNo, "调试");
        wf.log("【扫码支付-收款 请求参数】totalFee: "+totalFee, "调试");
        wf.log("【扫码支付-收款 请求参数】deviceInfo: "+deviceInfo, "调试");
        wf.log("【扫码支付-收款 请求参数】spBillCreateIP: "+spBillCreateIP, "调试");
        wf.log("【扫码支付-收款 请求参数】timeStart: "+timeStart, "调试");
        wf.log("【扫码支付-收款 请求参数】timeExpire: "+timeExpire, "调试");
        wf.log("【扫码支付-收款 请求参数】goodsTag: "+goodsTag, "调试");

        String nonceStr = DesUtil.generate32Key();

        SortedMap<String,String> map = new TreeMap<>();
        map.put("service", service);
        map.put("version", version);
        map.put("charset", charset);
        map.put("sign_type", signType);
        map.put("mch_id", mchId);
        map.put("out_trade_no", outTradeNo);
        map.put("body", body);
        map.put("total_fee", String.valueOf(totalFee));
        map.put("mch_create_ip", spBillCreateIP);
        map.put("notify_url", notifyUrl);
        map.put("nonce_str", nonceStr);
        map.put("auth_code", authCode);

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + MD5Key, "utf-8");

        map.put("sign", sign);
        log.error("【扫码支付-收款 请求参数】:" + XmlUtils.parseXML(map));

        Map<String, String> resultMap = new HashedMap();
        if(ConConfig.isFormal()){
            wf.log("【扫码支付-收款】请求环境:生产环境", "调试");

            CloseableHttpResponse response = null;
            CloseableHttpClient client = null;
            try {
                HttpPost httpPost = new HttpPost(reqUrl);
                StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8");
                httpPost.setEntity(entityParams);
                httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
                client = HttpClients.createDefault();
                response = client.execute(httpPost);
                if (response != null && response.getEntity() != null) {
                    resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("扫码支付-收款】 请求时系统异常!");
            }
        }else {
            wf.log("【扫码支付-收款】请求环境:测试环境", "调试");
            resultMap = null;
        }

        log.error("【扫码支付-收款 响应参数】:" + XmlUtils.toXml(resultMap));

        PurchaseResult pr = new PurchaseResult();
        pr.setReqMsg("交易失败!");
        pr.setStatus(0);
        pr.setReqCode("0001");

        if(resultMap.isEmpty()){
            pr.setReqMsg("操作失败,系统未响应!");
            return pr;
        }

        //校验签名
        if(resultMap.containsKey("sign")){
            if(!SignUtils.checkParam(resultMap, MD5Key)) {
                pr.setReqMsg("交易失败,验证签名不通过!");
                return pr;
            }
        }

        String status = resultMap.get("status");
        String message = resultMap.get("message");

        if(status.equals("0")){//通讯成功
            String result_code = resultMap.get("result_code");
            if(result_code.equals("0")){//交易受理完成

                String pay_result = resultMap.get("pay_result");//支付结果:0—成功;其它—失败
                String pay_info = resultMap.get("pay_info");//支付结果信息,支付成功时为空
                String transaction_id = resultMap.get("transaction_id");//威富通交易号
                String out_transaction_id = resultMap.get("out_transaction_id");//第三方订单号
                String out_trade_no = resultMap.get("out_trade_no");//商户系统内部的定单号
                String total_fee = resultMap.get("total_fee");//总金额
                String bank_type = resultMap.get("bank_type");//银行类型
                String bank_billno = resultMap.get("bank_billno");//银行订单号,若为微信支付则为空
                String time_end = resultMap.get("time_end");//支付完成时间

                if(!out_trade_no.equals(scanCodePayParam.getOutTradeNo())){
                    wf.log("响应商户订单号"+out_trade_no+"与请求商户订单号"+scanCodePayParam.getOutTradeNo()+"不匹配,请与接口管理人员联系!", "调试");
                    return pr;
                }

                if(!total_fee.equals(scanCodePayParam.getTotalFee())){
                    wf.log("收款响应金额"+total_fee+"与收款请求金额"+scanCodePayParam.getTotalFee()+"不匹配,请与接口管理人员联系!", "调试");
                    return pr;
                }

                pr.setBankRef(transaction_id);
                pr.setBankTransTime(time_end);
                pr.setAcquirers(bank_type);
                pr.setBankOrderNum(bank_billno);
                pr.setAuthorizationCode(out_transaction_id);

                if(pay_result.equals("0")){//支付成功
                    pr.setStatus(1);
                    pr.setReqCode("0000");
                    pr.setReqMsg("交易成功!");
                }else {
                    XYScanCodePayServiceImpl scanCodePayService = new XYScanCodePayServiceImpl();
                    int index = 0;
                    final int count = 6;
                    RevocationResult revocationResult;
                    do{
                        index++;
                        Thread.sleep(5*1000);
                        revocationResult = scanCodePayService.queryorder(scanCodePayParam.getOutTradeNo());
                        //等待用户输入支付密码
                        if(revocationResult.getReqCode().equals("0005")){
                            revocationResult=scanCodePayService.queryorder(scanCodePayParam.getOutTradeNo());
                            //如果用户的订单状态不是输入支付密码 直接跳出
                            if(!revocationResult.getReqCode().equals("0005")){
                                break;
                            }
                        }
                    }while(index<count);
                    //交易状态不成功走撤销
                    if(revocationResult.getReqCode().equals("0000")){
                        pr.setReqCode(revocationResult.getReqCode());
                        pr.setReqMsg(revocationResult.getReqMsg());
                        pr.setStatus(revocationResult.getStatus());
                    }else{
                        scanCodePayService.revocation(scanCodePayParam.getOutTradeNo());
                        pr.setReqMsg("连接超时,交易已撤销,请稍后再试!");
                    }

                    pr.setReqMsg(pay_info);
                }
            }else {
                String err_msg = resultMap.get("err_msg");
                String err_code = resultMap.get("err_code");
                pr.setReqMsg(err_msg);
                pr.setReqCode(err_code);
            }
        }else {
            pr.setReqMsg(message);
        }
        return pr;
    }

    /**
     * 冲正
     * @param out_trade_no 商户系统内部订单号
     * @return
     * @throws Exception
     */
    public RevocationResult revocation(String out_trade_no)throws Exception {

        String reqUrl = "https://pay.swiftpass.cn/pay/gateway";
        String service = "unified.micropay.reverse";

        log.error("【扫码支付-冲正 请求参数】out_trade_no: " + out_trade_no);
        wf.log("【扫码支付-冲正 请求参数】out_trade_no: " + out_trade_no, "调试");

        String nonceStr = DesUtil.generate32Key();

        SortedMap<String,String> map = new TreeMap<>();
        map.put("service", service);
        map.put("version", version);
        map.put("charset", charset);
        map.put("sign_type", signType);
        map.put("mch_id", mchId);
        map.put("nonce_str", nonceStr);
        map.put("out_trade_no",out_trade_no);

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + MD5Key, "utf-8");

        map.put("sign",sign);

        log.error("【扫码支付-冲正 请求参数】:" + XmlUtils.parseXML(map));

        Map<String, String> resultMap = new HashedMap();
        if(ConConfig.isFormal()){
            CloseableHttpResponse response = null;
            CloseableHttpClient client = null;
            try {
                HttpPost httpPost = new HttpPost(reqUrl);
                StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8");
                httpPost.setEntity(entityParams);
                httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
                client = HttpClients.createDefault();
                response = client.execute(httpPost);
                if (response != null && response.getEntity() != null) {
                    resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("扫码支付-冲正】 请求时系统异常!");
            }
        }else {
            //TODO:补充范例
            resultMap = null;
        }

        log.error("【扫码支付-冲正 响应参数】:" + XmlUtils.toXml(resultMap));

        RevocationResult rr = new RevocationResult();
        rr.setReqCode("0001");
        rr.setReqMsg("交易撤消失败!");
        rr.setStatus(0);

        if(resultMap.isEmpty()){
            rr.setReqMsg("操作失败,系统未响应!");
            return rr;
        }

        //校验签名
        if(resultMap.containsKey("sign")){
            if(!SignUtils.checkParam(resultMap, MD5Key)) {
                rr.setReqMsg("验证签名不通过!");
                return rr;
            }
        }

        String status = resultMap.get("status");
        String message = resultMap.get("message");

        if(StringUtils.isNotBlank(message)){
            rr.setReqMsg(message);
            return rr;
        }

        if(status.equals("0")){
            String result_code  = resultMap.get("result_code");
            if(result_code.equals("0")){
                rr.setReqCode("0000");
                rr.setReqMsg("交易撤消成功!");
                rr.setStatus(1);
            }
        }else {
            String err_code = resultMap.get("err_code");
            rr.setReqMsg(err_code);
        }
        return rr;
    }


    /**
     * 查询交易订单
     * @param out_trade_no 商户系统内部订单号
     * @return RevocationResult
     * @throws Exception
     */
    public RevocationResult queryorder(String out_trade_no)throws Exception {

        String reqUrl = "url:https://pay.swiftpass.cn/pay/gateway";
        String service = "unified.trade.query";

        log.error("【扫码支付-查询 请求参数】out_trade_no: " + out_trade_no);
        wf.log("【扫码支付-查询 请求参数】out_trade_no: " + out_trade_no, "调试");

        String nonceStr = DesUtil.generate32Key();

        SortedMap<String,String> map = new TreeMap<>();
        map.put("service", service);
        map.put("version", version);
        map.put("charset", charset);
        map.put("sign_type", signType);
        map.put("mch_id", mchId);
        map.put("nonce_str", nonceStr);
        map.put("out_trade_no",out_trade_no);

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + MD5Key, "utf-8");

        map.put("sign",sign);
        log.error("【扫码支付-查询 请求参数】:" + XmlUtils.parseXML(map));

        Map<String, String> resultMap = new HashedMap();

        if(ConConfig.isFormal()){
            CloseableHttpResponse response = null;
            CloseableHttpClient client = null;
            try {
                HttpPost httpPost = new HttpPost(reqUrl);
                StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8");
                httpPost.setEntity(entityParams);
                httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
                client = HttpClients.createDefault();
                response = client.execute(httpPost);
                if (response != null && response.getEntity() != null) {
                    resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("扫码支付-订单查询】 请求时系统异常!");
            }
        }else {
            resultMap = null;
        }

        log.error("【扫码支付-查询 响应参数】:" + XmlUtils.toXml(resultMap));

        RevocationResult rr = new RevocationResult();
        rr.setReqCode("0001");
        rr.setReqMsg("查询交易订单失败!");
        rr.setStatus(0);

        if(resultMap.isEmpty()){
            rr.setReqMsg("操作失败,系统未响应!");
            return rr;
        }

        //校验签名
        if(resultMap.containsKey("sign")){
            if(!SignUtils.checkParam(resultMap, MD5Key)) {
                rr.setReqMsg("验证签名不通过!");
                return rr;
            }
        }

        String status = resultMap.get("status");
        String message = resultMap.get("message");

        if(status.equals("0")){
            String result_code = resultMap.get("result_code");
            if(result_code.equals("0")){
                String trade_state = resultMap.get("trade_states");
                if(trade_state.equals("SUCCESS")){
                    rr.setReqCode("0000");
                    rr.setReqMsg("交易成功!");
                    rr.setStatus(1);
                }else if(trade_state.equals("NOTPAY")){
                    rr.setReqCode("0002");
                    rr.setReqMsg("交易失败,请确认是否输入支付密码 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("CLOSED")){
                    rr.setReqCode("0003");
                    rr.setReqMsg("交易已关闭 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("REVOKED") || trade_state.equals("REFUND")){
                    rr.setReqCode("0004");
                    rr.setReqMsg("交易已撤销 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("PAYERROR")){
                    rr.setReqCode("0001");
                    rr.setReqMsg("交易失败 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("USERPAYING")){
                    rr.setReqCode("0005");
                    rr.setReqMsg("用户交易中!");
                    rr.setStatus(0);
                }
            }else {
                String err_msg = resultMap.get("err_msg");
                String err_code = resultMap.get("err_code");
                rr.setReqMsg(err_msg);
                rr.setReqCode(err_code);
            }
        }else {
            rr.setReqMsg(message);
        }
        return rr;
    }

}
